/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Rozvrh;

import java.awt.Choice;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.TreeMap;

/**
 *  Trieda obsahujúca a pracujúca s informáciami o mesiaci, zamestnancoch a klientoch v danom mesiaci 
 * pre správne zostavenie rozvrhu. Obsahuje: rok, mesiac, počet dní mesiaca, koeficiant klientov
 * charakter jednitlivých dní, nastavenie jednotlivých zamestnancov, množina zamestnancov pracujúcich v daný
 * mesiac
 * @author MartinaHlinková
 */
public class InformacieOMesiaci implements Comparable<InformacieOMesiaci>{
    private InformacnaStruktura.Mesiac mesiac;
    private int optimalnyPocetMinut;
    private int rok;
    private int pocetDni;
    private Integer[] klientiVDnoch;
    private InformacnaStruktura.CharakterDna[] charakterDni;
    private HashMap<Integer,Rozvrh.NastavenieZamestnancaMesiac> nastavenieZamestnancov;
    private TreeMap<Integer,Sablony.Zamestnanec>mnozinaZamestnancov;
    
    /**
     * Optimálny počet minút, ktorý by mal byť odpracovaný zamestnancom v nevíkendový deň
     * 7 hodin 30 minut - vypocet z 37,5 hodiny do pracovneho tyzdna
     */
    public final int POCET_MINUT_OPTIMUM_DEN =450;
    
    /**
     * Maximálny počet minút, ktorý by mal byť odpracovaný zamestnancom v nevíkendový deň
     * Nie je súčasťou kontroly, teda zamestnanec môže odpracovať aj viac hodín za deň ale počíta sa z neho
     * maximálny počet minút za týždeň a mesiac.
     * 9 hodin 30 minut - vypocet z 48 hodiny do pracovneho tyzdna
     */
    public final int POCET_MINUT_MAX_DEN =576; //9 hodin 36 minut - vypocet 48 hodin do pracovneho tyzdna
    /**
     * Konštruktor objektov triedy InformacieOMesiaci. Transformuje informácie zo šablón zamestnancov a klientov
     * a vypočítava informácie o mesiaci cez dátumy
     * @param pociatok  počiatočný dámun mesiaca, z ktorého sa majú vypočítavať informácie
     * @param zamestnanci   šablóna zamestnancov, ktorí pracujú v daný mesiac
     * @param nastavenie    nastavenie zamestnancov, ktorí pracujú v daný mesiac
     * @param klienti   šablóna klientov, ktorí sú prítomní daný mesiac
     */
    public InformacieOMesiaci(Date pociatok,Sablony.SablonaZamestnancov zamestnanci,HashMap<Integer,Integer[]>nastavenie,Sablony.SablonaKlientov klienti){
        InformacnaStruktura.Mesiac[] mesiace = InformacnaStruktura.Mesiac.values();
        //nastavenia mesiaca
        for(InformacnaStruktura.Mesiac iterator:mesiace){
            if(pociatok.getMonth() == iterator.getPoradieMesiaca()){
                this.mesiac = iterator;
                //System.out.println(this.mesiac.toString() + " " +pociatok.getMonth());
                break;
            }  
            
        }
       //nastavenie roku
        this.rok = pociatok.getYear()+1900;
        //nastavenie poctu dni
        if(mesiac != InformacnaStruktura.Mesiac.FEBRUAR){
            this.pocetDni = mesiac.getPocetDni();
        }else{
            if((this.rok)%4 == 0){
                this.pocetDni = 29;
            }else this.pocetDni = 28;
        }
        
       //nastavenie charakteru dni(typ dna pracovny/volny)
        int pracovneDni=0;
        this.charakterDni = new InformacnaStruktura.CharakterDna[this.pocetDni];
        for(int i = 1; i<= this.pocetDni;i++){
            Date datumCopy = (Date)pociatok.clone();
            datumCopy.setDate(i);
            if(datumCopy.getDay() == 0 || datumCopy.getDay() == 6){
                this.charakterDni[i-1] = InformacnaStruktura.CharakterDna.VOLNY;
            }else{
                this.charakterDni[i-1] = InformacnaStruktura.CharakterDna.PRACOVNY;
                pracovneDni++;
            }
        }
        //vypocet optimalneho poctu hodin
        this.optimalnyPocetMinut = pracovneDni*450;
        
        //nastavenie poctu klientov v dnoch
        this.klientiVDnoch = new Integer[this.pocetDni];
        for(int i = 1; i <= this.pocetDni; i++){
           Date copy = (Date)pociatok.clone();
           copy.setDate(i);
           copy.setHours(12);
           this.klientiVDnoch[i-1] = klienti.pocetKlientovVDatume(copy); 
           
        }
        //nastavenie mnoziny zamestnancov a nastavenia zamestnancov
        this.mnozinaZamestnancov = new TreeMap<Integer,Sablony.Zamestnanec>();
        this.nastavenieZamestnancov = new HashMap<Integer,Rozvrh.NastavenieZamestnancaMesiac>();
        for(Sablony.Zamestnanec iterator: zamestnanci.getZamestnanciVSablone()){
            this.mnozinaZamestnancov.put(iterator.getIDZamestnanca(),iterator);
            Integer info[] = nastavenie.get(iterator.getIDZamestnanca());
            InformacnaStruktura.CasBezDatumu cas = new InformacnaStruktura.CasBezDatumu(info[1],info[2]);
            InformacnaStruktura.TypSalda saldo;
            if(info[0] < 0) saldo = InformacnaStruktura.TypSalda.NEDOPOCETNE;
            else saldo = InformacnaStruktura.TypSalda.NADPOCETNE;
            
            Rozvrh.NastavenieZamestnancaMesiac nove = new Rozvrh.NastavenieZamestnancaMesiac(cas,saldo);
            this.nastavenieZamestnancov.put(iterator.getIDZamestnanca(), nove);
        }
        
        
    }
    /**
     * Konštruktor objektov triedy InformacieOMesiaci. Priamo nastavuje rok, mesiac, pocetDni, 
     * pole koeficientov klientov, pole charakterov dní, nastavení zamestnancov a zamestnancov
     * @param rok   rok
     * @param mesiac    mesiac
     * @param pocetDni  počet dní
     * @param klienti   pole koeficientov klientov
     * @param charakter pole charakterov dní
     * @param nastavenie    nastavenie zamestnancov
     * @param zamestnanci zamestnanci
     */
    public InformacieOMesiaci(int rok, InformacnaStruktura.Mesiac mesiac, int pocetDni, Integer[] klienti,
            InformacnaStruktura.CharakterDna[] charakter, HashMap<Integer,Rozvrh.NastavenieZamestnancaMesiac> nastavenie,
            TreeMap<Integer,Sablony.Zamestnanec> zamestnanci){
    
        this.rok = rok;
        this.mesiac = mesiac;
        this.pocetDni = pocetDni;
        this.klientiVDnoch = klienti;
        this.charakterDni = charakter;
        this.nastavenieZamestnancov = nastavenie;
        this.mnozinaZamestnancov = zamestnanci;
        
        
        
        //vypocet pracovnych dni(typ dna pracovny/volny)
        int pracovneDni=0;
        Date datumCopy = (Date)new Date(this.rok,this.mesiac.getPoradieMesiaca(),1);
       
        for(int i = 1; i<= this.pocetDni;i++){
           
            datumCopy.setDate(i);
            if(datumCopy.getDay() == 0 || datumCopy.getDay() == 6){
                
            }else{
                
                pracovneDni++;
            }
        }
        
        this.optimalnyPocetMinut = pracovneDni*450;
        
    }
    /**
     * Metóda, ktorá vracia pole charakterov dní mesiaca
     * @return charaktery dní mesiaca
     */
    public InformacnaStruktura.CharakterDna[] getCharakterDni(){
        return this.charakterDni;
    }
    /**
     * Metóda, ktorá vracia počet dní mesiaca
     * @return počet dní mesiaca
     */
    public int getPocetDni(){
        return this.pocetDni;
    }
    /**
     * Metóda, ktorá vracia Mapu s kľúčami identifikačné čísla zamestnancov a hodnotami
     * zamestnancov
     * @return mapa zamestnancov
     */
    public TreeMap<Integer,Sablony.Zamestnanec> getMnozinaZamestnancov(){
        return this.mnozinaZamestnancov;
    }
    /**
     * Metóda, ktorá vráti počet zamestnancov
     * @return počet zamestnancov
     */
    public int pocetZamestnancov(){
        return this.mnozinaZamestnancov.size();
    }
    /**
     * Metóda, ktorá vracia pole koeficientov klientov vo všetkých dňoch mesiaca
     * @return pole koeficiantov kientov
     */
    public Integer[] getKlientiVDnoch(){
        return this.klientiVDnoch;
    }
    /**
     * Metóda, ktorá vracia mapu s kľúčmi identifikačné čísla zamestnancov a hodnotami
     * nastavenia zamestnancov. Vracia nastavenia všetkých zamestnancov v mesiaci.
     * @return nastaenia všetkých zamestnancov v mesiaci
     */
    public HashMap<Integer,Rozvrh.NastavenieZamestnancaMesiac> getNastavenieZamestnancov(){
        return this.nastavenieZamestnancov;
    }
    
    @Override
    public int compareTo(InformacieOMesiaci o) {
        if(this.getRok() > o.getRok())return -1;
        else if(this.getRok() < o.getRok()) return 1;
        else{
            if(this.getMasiac().getPoradieMesiaca() > o.getMasiac().getPoradieMesiaca())return -1;
            else if (this.getMasiac().getPoradieMesiaca() < o.getMasiac().getPoradieMesiaca()) return 1;
            else return 0;
        }
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 41 * hash + (this.mesiac != null ? this.mesiac.hashCode() : 0);
        hash = 41 * hash + this.rok;
        return hash;
    }
    
    @Override
     public boolean equals(Object o){
        if(o == this){
            return true;
        }
        if(o instanceof InformacieOMesiaci == false){
            return false;
        }
        boolean rovnake = (this.getRok() == ((InformacieOMesiaci) o).getRok());
        if(rovnake == true){
            rovnake = (this.getMasiac() == ((InformacieOMesiaci) o).getMasiac());
        }else return false;
        return rovnake;
    }
     /**
      * Metóda, ktorá vracia rok
      * @return rok
      */
     public int getRok(){
         return this.rok;
     }
     /**
      * Metóda, ktorá vracia mesiac
      * @return mesiac
      */
     public InformacnaStruktura.Mesiac getMasiac(){
         return this.mesiac;
     }
     /**
      * Metóda, ktorá vracia optimálny počet minút, ktorý môže zamestnanec opracovať
      * @return optimálny počet minút
      */
     public int getOptimalnyPocetMinut(){
         return this.optimalnyPocetMinut;
     }
     /**
      * Metóda, ktorá vracia meximálny počet minút, ktorý môže zamestnanec odpracovať
      * @return meximálny počet minút
      */
     public int getMaximalnyPocetMinut(){
         return (optimalnyPocetMinut/this.POCET_MINUT_OPTIMUM_DEN)*this.POCET_MINUT_MAX_DEN;
     }
}
